package dk.mirasola.systemtraining.user.client.ui.createbiddingsetwizard;


import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestOracle;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import dk.mirasola.systemtraining.user.client.i18n.CreateBiddingSetWizardTexts;
import dk.mirasola.systemtraining.user.client.ui.wizard.WizardStep;
import dk.mirasola.systemtraining.user.client.util.UserAsyncCallback;
import dk.mirasola.systemtraining.user.shared.service.UserService;
import dk.mirasola.systemtraining.user.shared.service.UserServiceAsync;
import dk.mirasola.systemtraining.user.shared.transfer.CreateBiddingSetTO;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class DetailsStep implements WizardStep {
    interface DetailsStepUiBinder extends UiBinder<Widget,DetailsStep>{}
    private static DetailsStepUiBinder uiBinder = GWT.create(DetailsStepUiBinder.class);
    private static UserServiceAsync userService = GWT.create(UserService.class);

    @UiField
    TextBox nameEditor;
    @UiField
    TextArea descriptionEditor;
    @UiField
    Label board10;
    @UiField
    Label board20;
    @UiField
    Label board30;
    @UiField
    Label board40;
    @UiField
    Label board50;
    @UiField
    CheckBox northMe;
    @UiField(provided = true)
    SuggestBox northEmail;
    @UiField
    CheckBox southMe;
    @UiField(provided = true)
    SuggestBox southEmail;
    @UiField
    HTML nameLabel;
    @UiField
    HTML descriptionLabel;
    @UiField
    HTML boardsLabel;
    @UiField
    HTML northBidderLabel;
    @UiField
    HTML southBidderlabel;
    @UiField
    InlineHTML northMeBidderLabel;
    @UiField
    InlineHTML northEmailLabel;
    @UiField
    InlineHTML southMeBidderLabel;
    @UiField
    InlineHTML southEmailLabel;

    private MultiWordSuggestOracle emailSuggest;
    private Button nextButton;
    private Button backButton;
    private Button finishButton;
    private CreateBiddingSetTO createBiddingSetTO;
    private CreateBiddingSetWizardTexts texts;
    private Widget stepWidget;
    private List<Label> boards;
    private List<String> emailSuggests;

    DetailsStep(CreateBiddingSetTO createBiddingSetTO, CreateBiddingSetWizardTexts texts, final Button nextButton, Button backButton, Button finishButton) {
        this.nextButton = nextButton;
        this.backButton = backButton;
        this.finishButton = finishButton;
        this.createBiddingSetTO = createBiddingSetTO;
        this.texts = texts;

        emailSuggest = new MultiWordSuggestOracle();
        northEmail = new SuggestBox(emailSuggest);
        southEmail = new SuggestBox(emailSuggest);

        stepWidget = uiBinder.createAndBindUi(this);
        nameLabel.setHTML(texts.nameLabel());
        descriptionLabel.setHTML(texts.descriptionLabel());
        boardsLabel.setHTML(texts.boardsLabel());
        northBidderLabel.setHTML(texts.northBidderLabel());
        northMeBidderLabel.setHTML(texts.meBidderLabel());
        northEmailLabel.setHTML(texts.bidderEmailLabel());
        southBidderlabel.setHTML(texts.southBidderLabel());
        southMeBidderLabel.setHTML(texts.meBidderLabel());
        southEmailLabel.setHTML(texts.bidderEmailLabel());

        boards = Arrays.asList(board10, board20, board30, board40, board50);

        initNameEditor();
        initBoardLabels();
        initBidder();
        initFinishHandler();
    }

    private void initFinishHandler() {
        finishButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                Set<String> newEmails = new HashSet<String>();
                if (createBiddingSetTO.getNorthEmail() != null && !emailSuggests.contains(createBiddingSetTO.getNorthEmail())) {
                    newEmails.add(createBiddingSetTO.getNorthEmail());
                }
                if (createBiddingSetTO.getSouthEmail() != null && !emailSuggests.contains(createBiddingSetTO.getSouthEmail())) {
                    newEmails.add(createBiddingSetTO.getSouthEmail());
                }
                if (newEmails.size() > 0) {
                    userService.addSuggestEmails(newEmails,new UserAsyncCallback<Void>() {
                        @Override
                        public void onSuccess(Void result) {
                            // do nothing
                        }
                    });
                }
            }
        });
    }


    private void initBidder() {
        northMe.setValue(true);
        northMe.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (northMe.getValue()) {
                    northEmailLabel.setVisible(false);
                    northEmail.setVisible(false);
                    createBiddingSetTO.setNorthEmail(null);
                } else {
                    northEmailLabel.setVisible(true);
                    northEmail.setVisible(true);
                    createBiddingSetTO.setNorthEmail(northEmail.getText());
                    if (!validateEmail(northEmail.getText())) {
                        northEmail.addStyleDependentName("invalid");
                    } else {
                        northEmail.removeStyleDependentName("invalid");
                    }

                }
                updateNextButton();
            }
        });

        northEmailLabel.setVisible(false);
        northEmail.setVisible(false);
        northEmail.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                onNorthEmailChange();
            }
        });
        northEmail.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
            @Override
            public void onSelection(SelectionEvent<SuggestOracle.Suggestion> suggestionSelectionEvent) {
                onNorthEmailChange();
            }
        });

        southMe.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (southMe.getValue()) {
                    southEmailLabel.setVisible(false);
                    southEmail.setVisible(false);
                    createBiddingSetTO.setSouthEmail(null);
                } else {
                    southEmailLabel.setVisible(true);
                    southEmail.setVisible(true);
                    createBiddingSetTO.setSouthEmail(southEmail.getText());
                    if (!validateEmail(southEmail.getText())) {
                        southEmail.addStyleDependentName("invalid");
                    } else {
                        southEmail.removeStyleDependentName("invalid");
                    }
                }
                updateNextButton();
            }
        });

        southEmail.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                onSouthEmailChange();
            }
        });
        southEmail.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
            @Override
            public void onSelection(SelectionEvent<SuggestOracle.Suggestion> suggestionSelectionEvent) {
                onSouthEmailChange();
            }
        });

        userService.getEmailSuggest(new UserAsyncCallback<List<String>>() {
            @Override
            public void onSuccess(List<String> result) {
                emailSuggest.addAll(result);
                emailSuggests = result;

                if (result.size() > 0) {
                    createBiddingSetTO.setSouthEmail(result.get(0));
                    southEmail.setText(result.get(0));
                } else {
                    createBiddingSetTO.setSouthEmail("partner@host.com");
                    southEmail.setText("partner@host.com");
                }
            }
        });
    }

    private void onNorthEmailChange() {
        updateNextButton();
        if (!validateEmail(northEmail.getText())) {
            northEmail.addStyleDependentName("invalid");
        } else {
            northEmail.removeStyleDependentName("invalid");
        }
        createBiddingSetTO.setNorthEmail(northEmail.getText());
    }

    private void onSouthEmailChange() {
        updateNextButton();
        if (!validateEmail(southEmail.getText())) {
            southEmail.addStyleDependentName("invalid");
        } else {
            southEmail.removeStyleDependentName("invalid");
        }
        createBiddingSetTO.setSouthEmail(southEmail.getText());
    }

    private void initNameEditor() {
        nameEditor.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                updateNextButton();
                if (nameEditor.getText().length() == 0) {
                    nameEditor.addStyleDependentName("invalid");
                } else {
                    nameEditor.removeStyleDependentName("invalid");
                }
                createBiddingSetTO.setName(nameEditor.getText());
            }
        });
    }

    private void initBoardLabels() {
        for (final Label boardLabel : boards) {
            if (boardLabel.getText().equals(String.valueOf(createBiddingSetTO.getBoards()))) {
                boardLabel.addStyleDependentName("selected");
            } else {
                boardLabel.removeStyleDependentName("selected");
            }

            boardLabel.addMouseOverHandler(new MouseOverHandler() {
                @Override
                public void onMouseOver(MouseOverEvent event) {
                    if (!boardLabel.getText().equals(String.valueOf(createBiddingSetTO.getBoards()))) {
                        boardLabel.addStyleDependentName("mouseover");
                    }
                }
            });

            boardLabel.addMouseOutHandler(new MouseOutHandler() {
                @Override
                public void onMouseOut(MouseOutEvent event) {
                    boardLabel.removeStyleDependentName("mouseover");
                }
            });

            boardLabel.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    for (Label label : boards) {
                        label.removeStyleDependentName("selected");
                    }
                    boardLabel.addStyleDependentName("selected");

                    int selBoards = Integer.valueOf(boardLabel.getText());
                    createBiddingSetTO.setBoards(selBoards);

                    while (createBiddingSetTO.getDistributions().size() > selBoards) {
                        createBiddingSetTO.getDistributions().remove(0);
                    }

                    if (nextButton.isEnabled()) {
                        nextButton.setFocus(true);
                    } else {
                        nameEditor.setFocus(true);
                    }
                }
            });
        }
    }

    public SafeHtml getProgressText() {
        return texts.detailsStepProgressText();
    }

    public Widget getWidget() {
        return stepWidget;
    }

    private void updateNextButton() {
        nextButton.setEnabled(nameEditor.getText().length() > 0 &&
                (northMe.getValue() || validateEmail(northEmail.getText())) &&
                (southMe.getValue() || validateEmail(southEmail.getText())));
    }

    private boolean validateEmail(String email) {
        return email.matches("^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$");
    }

    public void activate() {
        nameEditor.setText(createBiddingSetTO.getName());
        descriptionEditor.setText(createBiddingSetTO.getDescription());
        updateNextButton();
        backButton.setEnabled(true);
        nameEditor.setFocus(true);
    }
}